﻿using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;

namespace Koala.Pro.Common
{
    [Flags]
    public enum InternetConnectionStatesType
    {
        ModemConnection = 1,
        LANConnection = 2,
        ProxyConnection = 4,
        RASInstalled = 0x10,
        Offline = 0x20,
        ConnectionConfigured = 0x40
    }

    public class NetworkUtil
    {
        public static string LocalHostName => Dns.GetHostName();

        public static string LANIP
        {
            get
            {
                IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                if (addressList.Length < 1)
                {
                    return "";
                }
                return addressList[0].ToString();
            }
        }

        public static string WANIP
        {
            get
            {
                IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                if (addressList.Length < 2)
                {
                    return "";
                }
                return addressList[1].ToString();
            }
        }

        public static InternetConnectionStatesType CurrentState
        {
            get
            {
                InternetConnectionStatesType lpdwFlags = (InternetConnectionStatesType)0;
                InternetGetConnectedState(ref lpdwFlags, 0);
                return lpdwFlags;
            }
        }

        public static List<string> GetMacAddress(string separator = "-")
        {
            NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            if (allNetworkInterfaces == null || allNetworkInterfaces.Length < 1)
            {
                return null;
            }
            List<string> list = new List<string>();
            foreach (NetworkInterface item in allNetworkInterfaces.Where((NetworkInterface c) => c.NetworkInterfaceType != NetworkInterfaceType.Loopback && c.OperationalStatus == OperationalStatus.Up))
            {
                if (item.GetIPProperties().UnicastAddresses.Any((UnicastIPAddressInformation temp) => temp.Address.AddressFamily == AddressFamily.InterNetwork))
                {
                    PhysicalAddress physicalAddress = item.GetPhysicalAddress();
                    if (string.IsNullOrEmpty(separator))
                    {
                        list.Add(physicalAddress.ToString());
                    }
                    else
                    {
                        list.Add(string.Join(separator, physicalAddress.GetAddressBytes()));
                    }
                }
            }
            return list;
        }

        public static string GetMacAddress2()
        {
            NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            string result = "";
            NetworkInterface[] array = allNetworkInterfaces;
            foreach (NetworkInterface adapter in array)
            {
                if (IsEthernet(adapter))
                {
                    result = GetMacAddr(adapter);
                }
            }
            return result;
        }

        private static string GetMacAddr(NetworkInterface adapter)
        {
            string text = "";
            byte[] addressBytes = adapter.GetPhysicalAddress().GetAddressBytes();
            for (int i = 0; i < addressBytes.Length; i++)
            {
                text += addressBytes[i].ToString("X2");
                if (addressBytes.Length - 1 != i)
                {
                    text += ":";
                }
            }
            return text;
        }

        private static bool IsEthernet(NetworkInterface adapter)
        {
            if (NetworkInterfaceType.Ethernet == adapter.NetworkInterfaceType)
            {
                return true;
            }
            return false;
        }

        public static string GetPhysicalAddr(string cardId)
        {
            string text = string.Empty;
            uint num = 0u;
            try
            {
                num = Win32Utils.CreateFile("\\\\.\\" + cardId, 3221225472u, 3u, 0, 3u, 0u, 0);
                if (num != uint.MaxValue)
                {
                    byte[] array = new byte[6];
                    uint lpbytesReturned = 0u;
                    int lpInBuffer = 16843009;
                    if (Win32Utils.DeviceIoControl(num, 1507330u, ref lpInBuffer, 4, array, 6, ref lpbytesReturned, 0) != 0)
                    {
                        string empty = string.Empty;
                        byte[] array2 = array;
                        for (int i = 0; i < array2.Length; i++)
                        {
                            empty = Convert.ToString(array2[i], 16).PadLeft(2, '0');
                            text += empty;
                            empty = string.Empty;
                        }
                    }
                }
            }
            finally
            {
                if (num != 0)
                {
                    Win32Utils.CloseHandle(num);
                }
            }
            return text;
        }

        public static string GetIPAddress()
        {
            return (from p in (from p in NetworkInterface.GetAllNetworkInterfaces()
                               select p.GetIPProperties()).SelectMany((IPInterfaceProperties p) => p.UnicastAddresses)
                    where p.Address.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(p.Address)
                    select p).FirstOrDefault()?.Address.ToString();
        }

        public static string GetLocalIP()
        {
            return GetIPAddress();
        }

        public static string GetValidIP(string ip)
        {
            if (ValidateUtil.IsIP(ip))
            {
                return ip;
            }
            return "-1";
        }

        public static int GetValidPort(string port)
        {
            int num = -1;
            num = ConvertHelper.ConvertTo<int>(port);
            if (num <= 0 || num > 65535)
            {
                throw new ArgumentException("参数port端口号范围无效！");
            }
            return num;
        }

        public static IPAddress StringToIPAddress(string ip)
        {
            return IPAddress.Parse(ip);
        }

        public static bool IsInIp(string ip, string begip, string endip)
        {
            int[] array = new int[4];
            int[] ip2 = GetIp(ip);
            int[] ip3 = GetIp(begip);
            array = GetIp(endip);
            for (int i = 0; i < 4; i++)
            {
                if (ip2[i] < ip3[i] || ip2[i] > array[i])
                {
                    return false;
                }
                if (ip2[i] > ip3[i] || ip2[i] < array[i])
                {
                    return true;
                }
            }
            return true;
        }

        protected static int[] GetIp(string ip)
        {
            int[] array = new int[4];
            int i = 0;
            int num = 0;
            for (; i < ip?.Length; i++)
            {
                char c = ip[i];
                if (c != '.')
                {
                    array[num] = array[num] * 10 + int.Parse(c.ToString());
                }
                else
                {
                    num++;
                }
            }
            return array;
        }

        public static string GetClientIP(Socket clientSocket)
        {
            return ((IPEndPoint)clientSocket.RemoteEndPoint).Address.ToString();
        }

        public static IPEndPoint CreateIPEndPoint(string ip, int port)
        {
            return new IPEndPoint(StringToIPAddress(ip), port);
        }

        public static TcpListener CreateTcpListener()
        {
            return new TcpListener(new IPEndPoint(IPAddress.Any, 0));
        }

        public static TcpListener CreateTcpListener(string ip, int port)
        {
            return new TcpListener(new IPEndPoint(StringToIPAddress(ip), port));
        }

        public static Socket CreateTcpSocket()
        {
            return new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public static Socket CreateUdpSocket()
        {
            return new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        }

        public static IPEndPoint GetLocalPoint(TcpListener tcpListener)
        {
            return (IPEndPoint)tcpListener.LocalEndpoint;
        }

        public static string GetLocalPoint_IP(TcpListener tcpListener)
        {
            return ((IPEndPoint)tcpListener.LocalEndpoint).Address.ToString();
        }

        public static int GetLocalPoint_Port(TcpListener tcpListener)
        {
            return ((IPEndPoint)tcpListener.LocalEndpoint).Port;
        }

        public IList<IPEndPoint> GetUsedIPEndPoint()
        {
            IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] activeTcpListeners = iPGlobalProperties.GetActiveTcpListeners();
            IPEndPoint[] activeUdpListeners = iPGlobalProperties.GetActiveUdpListeners();
            TcpConnectionInformation[] activeTcpConnections = iPGlobalProperties.GetActiveTcpConnections();
            IList<IPEndPoint> list = new List<IPEndPoint>();
            IPEndPoint[] array = activeTcpListeners;
            foreach (IPEndPoint item in array)
            {
                list.Add(item);
            }
            array = activeUdpListeners;
            foreach (IPEndPoint item2 in array)
            {
                list.Add(item2);
            }
            TcpConnectionInformation[] array2 = activeTcpConnections;
            foreach (TcpConnectionInformation tcpConnectionInformation in array2)
            {
                list.Add(tcpConnectionInformation.LocalEndPoint);
            }
            return list;
        }

        public bool IsUsedIPEndPoint(int port)
        {
            foreach (IPEndPoint item in GetUsedIPEndPoint())
            {
                if (item.Port == port)
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsUsedIPEndPoint(string ip, int port)
        {
            foreach (IPEndPoint item in GetUsedIPEndPoint())
            {
                if (item.Address.ToString() == ip && item.Port == port)
                {
                    return true;
                }
            }
            return false;
        }

        public static IPEndPoint GetLocalPoint(Socket socket)
        {
            return (IPEndPoint)socket.LocalEndPoint;
        }

        public static string GetLocalPoint_IP(Socket socket)
        {
            return ((IPEndPoint)socket.LocalEndPoint).Address.ToString();
        }

        public static int GetLocalPoint_Port(Socket socket)
        {
            return ((IPEndPoint)socket.LocalEndPoint).Port;
        }

        public static void BindEndPoint(Socket socket, IPEndPoint endPoint)
        {
            if (!socket.IsBound)
            {
                socket.Bind(endPoint);
            }
        }

        public static void BindEndPoint(Socket socket, string ip, int port)
        {
            IPEndPoint localEP = CreateIPEndPoint(ip, port);
            if (!socket.IsBound)
            {
                socket.Bind(localEP);
            }
        }

        public static void StartListen(Socket socket, int port)
        {
            IPEndPoint endPoint = CreateIPEndPoint(LocalHostName, port);
            BindEndPoint(socket, endPoint);
            socket.Listen(100);
        }

        public static void StartListen(Socket socket, int port, int maxConnection)
        {
            IPEndPoint endPoint = CreateIPEndPoint(LocalHostName, port);
            BindEndPoint(socket, endPoint);
            socket.Listen(maxConnection);
        }

        public static void StartListen(Socket socket, string ip, int port, int maxConnection)
        {
            BindEndPoint(socket, ip, port);
            socket.Listen(maxConnection);
        }

        public static bool Connect(Socket socket, string ip, int port)
        {
            socket.Connect(ip, port);
            return socket.Poll(-1, SelectMode.SelectWrite);
        }

        public static void SendMsg(Socket socket, byte[] msg)
        {
            socket.Send(msg, msg.Length, SocketFlags.None);
        }

        public static void SendMsg(Socket socket, string msg)
        {
            byte[] array = ConvertHelper.StringToBytes(msg);
            socket.Send(array, array.Length, SocketFlags.None);
        }

        public static void ReceiveMsg(Socket socket, byte[] buffer)
        {
            socket.Receive(buffer);
        }

        public static string ReceiveMsg(Socket socket)
        {
            byte[] array = new byte[5000];
            int num = socket.Receive(array);
            byte[] array2 = new byte[num];
            Buffer.BlockCopy(array, 0, array2, 0, num);
            return ConvertHelper.BytesToString(array2);
        }

        public static void Close(Socket socket)
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
            }
            catch (SocketException ex)
            {
                throw ex;
            }
            finally
            {
                socket.Close();
            }
        }

        [DllImport("wininet")]
        private static extern bool InternetGetConnectedState(out int connectionDescription, int reservedValue);

        public static bool IsConnectedInternet()
        {
            int connectionDescription = 0;
            if (InternetGetConnectedState(out connectionDescription, 0))
            {
                return true;
            }
            return false;
        }

        [DllImport("WININET", CharSet = CharSet.Auto)]
        private static extern bool InternetGetConnectedState(ref InternetConnectionStatesType lpdwFlags, int dwReserved);

        public static bool IsOnline()
        {
            InternetConnectionStatesType currentState = CurrentState;
            return !IsFlagged(32, (int)currentState);
        }

        internal static bool IsFlagged(int flaggedEnum, int flaggedValue)
        {
            if ((flaggedEnum & flaggedValue) != 0)
            {
                return true;
            }
            return false;
        }

        public static string ConvertDnsToIp(string hostname)
        {
            IPHostEntry hostByName = Dns.GetHostByName(hostname);
            if (hostByName != null)
            {
                return hostByName.AddressList[0].ToString();
            }
            return null;
        }

        public static string ConvertIpToDns(string ipAddress)
        {
            return Dns.Resolve(ipAddress)?.HostName;
        }

        public static string GetHostName(IPEndPoint ipEndPoint)
        {
            return GetHostName(ipEndPoint.Address);
        }

        public static string GetHostName(IPAddress ip)
        {
            return GetHostName(ip.ToString());
        }

        public static string GetHostName(string hostIP)
        {
            try
            {
                return Dns.Resolve(hostIP).HostName;
            }
            catch
            {
            }
            return null;
        }

        public static EndPoint GetNetworkAddressEndPoing(IPHostEntry entry)
        {
            return new IPEndPoint(entry.AddressList[0], 0);
        }

        public static bool IsHostAvailable(string host)
        {
            return ResolveHost(host) != null;
        }

        public static IPHostEntry ResolveHost(string host)
        {
            try
            {
                return Dns.Resolve(host);
            }
            catch
            {
            }
            return null;
        }
    }
}

internal class Win32Utils
{
    public const string REG_NET_CARDS_KEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";

    public const uint GENERIC_READ = 2147483648u;

    public const uint GENERIC_WRITE = 1073741824u;

    public const uint FILE_SHARE_READ = 1u;

    public const uint FILE_SHARE_WRITE = 2u;

    public const uint OPEN_EXISTING = 3u;

    public const uint INVALID_HANDLE_VALUE = uint.MaxValue;

    public const uint IOCTL_NDIS_QUERY_GLOBAL_STATS = 1507330u;

    public const int PERMANENT_ADDRESS = 16843009;

    [DllImport("kernel32.dll")]
    public static extern int CloseHandle(uint hObject);

    [DllImport("kernel32.dll")]
    public static extern int DeviceIoControl(uint hDevice, uint dwIoControlCode, ref int lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, ref uint lpbytesReturned, int lpOverlapped);

    [DllImport("kernel32.dll")]
    public static extern uint CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, int lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, int hTemplateFile);
}